package com.wgo.bpot.server.integrationtest.conflict;

import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Scanner;

import remato.common.domain.helpers.Nameable;
import remato.domain.common.Category;
import remato.domain.common.Project;
import remato.domain.common.Requirement;
import remato.domain.common.RequirementSystem;
import remato.domain.common.Stakeholder;

import com.wgo.bpot.common.transport.exception.db.DatabaseException;
import com.wgo.bpot.domain.common.CommandHistory;
import com.wgo.bpot.server.integrationtest.remato.CrudBaseTest;
import com.wgo.precise.client.common.session.PreciseSession;
import com.wgo.precise.util.ConceptFactoryWrapper;
import com.wgo.precise.util.TestConfiguration;

public class ConflictApp extends CrudBaseTest {

	private PreciseSession session1;
	private ConceptFactoryWrapper conceptFactory1;
	private RequirementSystem rs1;
	private Project project1A;
	private String name = "" + System.currentTimeMillis();

	public static void main(String[] args) throws Exception {
		ConflictApp c = new ConflictApp();
		if (0 < args.length) {
			c.name = args[0];
			c.session1 = TestConfiguration.createNewSession();
			c.conceptFactory1 = new ConceptFactoryWrapper(c.session1);
			c.readConsoleInput();
		} else {
			System.out.println("Attempting to start server!");
			try {
				c.setUp();
				c.session1 = TestConfiguration.createNewSession();
				c.conceptFactory1 = new ConceptFactoryWrapper(c.session1);
				c.create();
				System.out.println("Successfully started server!");
			} catch (Throwable e) {
				e.printStackTrace();
			}
		}
	}

	private void readConsoleInput() throws Exception {
		System.out.println();
		boolean finished = false;
		Scanner scanner = new Scanner(System.in);
		while (!finished) {
			System.out
					.print("[" + name + "__ " + new Date().toString() + "] Command (c=create) (l=load) (m=modify and save) (r=remote) (h=history) (q=quit): ");
			try {
				String command = scanner.next().trim().toLowerCase();
				if ("c".equals(command)) {
					create();
				} else if ("l".equals(command)) {
					load();
				} else if ("m".equals(command)) {
					modify();
				} else if ("r".equals(command)) {
					remote();
				} else if ("h".equals(command)) {
					history();
				} else if ("q".equals(command)) {
					finished = true;
				}
				
			} catch (DatabaseException e) {
				if (e.getMessage().contains("stale")) {
					System.out.println("**********  Conflict detected!!! Data not saved!");
				} else {
					e.printStackTrace();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		scanner.close();
		tearDown();
	}

	private void remote() {
		Category cat = getCategoryA();
		int noRequirements = cat.serverCall().getNoRequirements();
		List<Requirement> allRequirements = cat.serverCall().getAllRequirements();
		System.out.println("Remote call: Number of requirements: " + noRequirements + "  allReqs.size=" + allRequirements.size());
	}

	private void history() {
		List<CommandHistory> commandHistory = session1.retrieveCommandHistory(project1A);
		for (CommandHistory history : commandHistory) {
			System.out.println(history.toString());
		}
	}

	private void modify() {
		if (null == project1A) {
			load();
		}
		String old = project1A.getDescription();
		project1A.setDescription("description modified by " + name + " at "
				+ new Date().toString());
		session1.save();
		System.out.println("Successfully modified description from \"" + old + "\" to \"" + project1A.getDescription() + "\"");
	}

	private void load() {
		session1 = TestConfiguration.createNewSession();
		conceptFactory1 = new ConceptFactoryWrapper(session1);
		rs1 = session1.getRootSystem(RequirementSystem.class);
		project1A = getNameable("project A", rs1.getProjectChildren());
		System.out.println("Successfully loaded description: \"" + project1A.getDescription() + "\"");
	}

	private void create() {
		session1.createDbSchema();
		buildLocalDatasetA(conceptFactory1);
		session1.save();
		System.out.println("Successfully created and saved new data.");
	}
	
	private Category getCategoryA(){
		if (null==project1A) {
			load();
		}
		Project subProjectB = getNameable("subProject B", project1A.getProjectChildren());
		return getNameable("category A", subProjectB.getCategoryChildren());
	}

	protected void buildLocalDatasetA(ConceptFactoryWrapper conceptFactory) {
		RequirementSystem requirementSystem = conceptFactory
				.getRequirementSystem();
		Project projectA = conceptFactory.createProject("project A");
		projectA.setDescription("Initial description");
		requirementSystem.addProjectChild(projectA);
		Project projectB = conceptFactory.createProject("project B");
		requirementSystem.addProjectChild(projectB);
		Project projectC = conceptFactory.createProject("project C");
		requirementSystem.addProjectChild(projectC);
		Project projectD = conceptFactory.createProject("project D");
		requirementSystem.addProjectChild(projectD);
		Project subProjectA = conceptFactory.createProject("subProject A");
		projectA.addProjectChild(subProjectA);
		Project subProjectB = conceptFactory.createProject("subProject B");
		projectA.addProjectChild(subProjectB);
		Stakeholder stakeholder = conceptFactory.createStakeholder();
		stakeholder.setFirstName("Stakeholder A");
		requirementSystem.addStakeholder(stakeholder);
		Category catA = conceptFactory.createCategory("category A");
		subProjectB.addCategoryChild(catA);
		Category catB = conceptFactory.createCategory("category B");
		subProjectB.addCategoryChild(catB);
		Category catC = conceptFactory.createCategory("subCategory C");
		catB.addCategoryChild(catC);
		Category catD = conceptFactory.createCategory("subCategory D");
		catB.addCategoryChild(catD);
		Category category = conceptFactory
				.createCategory("RequirementsCategory");
		projectC.addCategoryChild(category);
		catA.addRequirement(conceptFactory.createRequirement("req a"));
		catA.addRequirement(conceptFactory.createRequirement("req b"));
		catA.addRequirement(conceptFactory.createRequirement("req c"));
		Category catE = conceptFactory.createCategory("subCategory E");
		catE.addRequirement(conceptFactory.createRequirement("req d"));
		catE.addRequirement(conceptFactory.createRequirement("req e"));
		catE.addRequirement(conceptFactory.createRequirement("req f"));
		catE.addRequirement(conceptFactory.createRequirement("req g"));
		catE.addRequirement(conceptFactory.createRequirement("req h"));
		catA.addCategoryChild(catE);
	}

	protected static <T extends Nameable> T getNameable(String name,
			Collection<T> nameables) {
		for (T nameable : nameables) {
			if (name.equals(nameable.getName())) {
				return nameable;
			}
		}
		return null;
	}

}
